Load Data

library(ggplot2)
library(data.table)
library(scales)
library(RColorBrewer)

data_dir <- here::here('..','data')
load(file.path(data_dir, 'exh.sampled.Rdata'))

car_set <- c('41BB','CD28','BAFF-R','CD40','TACI')


# map day 0 to both plus and minus
map_day_0 <- function(df) {
  return(rbind(
    df[k562!='none'],
    df[k562=='none'][, k562 := 'cd19+'],
    df[k562=='none'][, k562 := 'cd19-']
  ))
}

Assess Marker Thresholds

# table of thresholds chosen
marker_thresholds <- rbind(
    c(exh_opt_cd4$marker_thresholds, t_type='cd4'),
    c(exh_opt_cd8$marker_thresholds, t_type='cd8'))
marker_thresholds <- melt(
    data.table(marker_thresholds), id.vars=c('t_type'))
marker_thresholds[, value := unlist(value)]
marker_thresholds[, t_type := unlist(t_type)]
marker_thresholds <- rbind(
    copy(marker_thresholds[, k562 := 'cd19+']), 
    copy(marker_thresholds[, k562 := 'cd19-']))

blue_shades <- brewer.pal(7, "YlGnBu")[3:7]

# assess marker thresholds
ggplot(exh_dt[k562 %in% c('cd19+','cd19-') & variable != 'zombie_t' & 
    variable %in% names(exh_opt_cd4$marker_thresholds)]) + 
    geom_density(aes(x=value, color=factor(day))) + 
    scale_x_continuous(limits=c(-1000,5000)) + 
    theme_minimal() +
    geom_vline(data=marker_thresholds[variable != 'zombie_t'], aes(xintercept=value)) +
    facet_grid(t_type+k562~variable, scale='free') + 
    scale_color_manual(values=blue_shades)

Summary Stats by MFI, % Positive, and % Positive MFI


# which markers for which summary stats
total_mfi <- c('cd39_t','myc_t', 'pd1_t')
pos_mfi <- c('tim3_t','lag3_t','cd39_t','pd1_t')
pos_pct <- c('tim3_t','lag3_t','cd39_t', 'pd1_t')

pct_pos_markers <- exh_dt[variable %in% pos_pct,
  list(pct_pos= sum(gt_thresh)/.N),
  by=c('plate','well','day','k562','donor','car','variable','t_type')][, 
    list(mean_pct_pos= mean(pct_pos), sd_pct_pos= sd(pct_pos)),
    by=c('day','k562','donor','car','variable','t_type')]
pct_pos_markers <- map_day_0(pct_pos_markers)

pos_mfi_markers <- exh_dt[variable %in% pos_mfi,
  list(pos_mfi_well= mean(value[gt_thresh==T]), pos_mfi_well_sd= sd(value[gt_thresh==T])), 
  by=c('plate','well','day','k562','donor','car','variable','t_type')][,
    `:=`(mean_mfi_pos= mean(pos_mfi_well), sd_mfi_pos= sd(pos_mfi_well)),
        by=c('day','k562','donor','car','variable','t_type')]  
    
pct_pos_markers[, mean_diff_pct_pos := mean_pct_pos-mean(mean_pct_pos, na.rm=T), 
    by=c('day','k562','donor','variable','t_type')]

pct_pos_lbls <- pct_pos_markers[!is.na(variable) & !is.na(donor) & k562 == 'cd19+',
  list(var_mean = mean(mean_pct_pos, na.rm=T)), by=c('k562','day','variable','donor','t_type')][,
    variable := as.character(variable)]

# all CARs, CD19+ only

ggplot(pct_pos_markers[!is.na(variable) & !is.na(donor) & k562 == 'cd19+' & variable %in% pos_pct]) + 
    geom_bar(aes(x=car, y=mean_diff_pct_pos, fill=variable), stat='identity') +
    geom_linerange(aes(x=car, ymin=mean_diff_pct_pos-sd_pct_pos, ymax=mean_diff_pct_pos+sd_pct_pos)) +
    geom_text(data=pct_pos_lbls, 
        aes(label=percent(round(var_mean,3))), y=Inf, x=-Inf, hjust=0, vjust=1) + 
    facet_grid(variable+donor~day+t_type, scales='free') +
    theme_minimal(base_size=18) + scale_y_continuous(labels = percent_format(accuracy = 1)) +
    theme(axis.text.x=element_text(angle = 90, hjust = 1)) +
    labs(x='CAR', y='Change in % Positive', title='Pct % in Exhaustion Marker from Average CAR (All CARs)') +
    geom_hline(yintercept=0) +
    geom_vline(xintercept=-Inf)


# selected car set only, CD19+ only

pct_pos_markers[car %in% car_set, mean_diff_pct_pos := mean_pct_pos-mean(mean_pct_pos, na.rm=T), 
    by=c('day','k562','donor','variable','t_type')]

pct_pos_lbls <- pct_pos_markers[car %in% car_set & !is.na(variable) & !is.na(donor) & k562 == 'cd19+',
  list(var_mean = mean(mean_pct_pos, na.rm=T)), by=c('k562','day','variable','donor','t_type')][,
    variable := as.character(variable)]

ggplot(pct_pos_markers[car %in% car_set & !is.na(variable) & !is.na(donor) & k562 == 'cd19+' & variable %in% pos_pct]) + 
    geom_bar(aes(x=car, y=mean_diff_pct_pos, fill=variable), stat='identity') +
    geom_linerange(aes(x=car, ymin=mean_diff_pct_pos-sd_pct_pos, ymax=mean_diff_pct_pos+sd_pct_pos)) +
    geom_text(data=pct_pos_lbls, 
        aes(label=percent(round(var_mean,3))), y=Inf, x=-Inf, hjust=0, vjust=1) + 
    facet_grid(variable+donor~t_type + day, scales='free') +
    theme_minimal(base_size=18) + scale_y_continuous(labels = percent_format(accuracy = 1)) +
    theme(axis.text.x=element_text(angle = 90, hjust = 1)) +
    labs(x='CAR', y='Change in % Positive', title='Pct % in Exhaustion Marker from Average CAR (Selected CARs)') +
    geom_hline(yintercept=0) +
    geom_vline(xintercept=-Inf)

Number of positive markers per cell

marker_ct <- exh_dt[variable %in% c('tim3_t','lag3_t','cd39_t', 'pd1_t'),
  list(n_pos_marker= sum(gt_thresh)), 
  by=c('well','plate','day','Time','car','donor','k562','t_type')]

marker_ct <- marker_ct[, N := .N, by=c('well','plate','day','car','k562','t_type')][N > 1]

marker_ct <- map_day_0(marker_ct)

marker_freq <- marker_ct[, data.frame(table(factor(n_pos_marker, levels= 0:4))), 
  by=c('well','plate','day','car','donor','k562','t_type')]
names(marker_freq)[names(marker_freq) == 'Var1'] <- 'n_pos_marker'

marker_freq[ n_pos_marker != 7, pct := Freq/sum(Freq), 
  by=c('well','plate','day','car','donor','k562','t_type')]

marker_freq <- marker_freq[,
  list(mean_pct= mean(pct, na.rm=T)),
  by=c('day','car','donor','k562', 'n_pos_marker','t_type')]

ggplot(marker_freq[k562 != 'none' & n_pos_marker != 7]) + 
  geom_bar(aes(x=car, y=mean_pct, fill=n_pos_marker), stat='identity') + 
  facet_grid(k562 + donor + t_type ~ day, scales='free') + 
  scale_y_continuous(expand=c(0,0)) + 
  scale_fill_brewer('Number of Exh.\nMarkers Present', palette='YlOrRd') + 
  theme_minimal() +
  labs(x="CAR", y='Fraction of Cells')

ggplot(marker_freq[k562 != 'none' & n_pos_marker != 7 & k562 == 'cd19+']) + 
  geom_bar(aes(x=factor(day), y=mean_pct, fill=n_pos_marker), stat='identity', width=1) + 
  facet_grid(donor ~ t_type + car, scales='free') + 
  scale_y_continuous(expand=c(0,0), labels = percent_format(accuracy = 1)) + 
  scale_x_discrete(expand=c(0,0)) +
  scale_fill_brewer('Number of Exh.\nMarkers Present', palette='YlOrRd') + 
  theme_minimal() +
  geom_vline(xintercept=0:7-0.5) +
  geom_hline(yintercept=c(0,1)) +
  labs(x="CAR", y='Fraction of Cells')

# pie charts
ggplot(marker_freq[donor == 1 & k562 != 'none' & n_pos_marker != 7 & k562 == 'cd19+']) + 
    geom_bar(aes(x=1, y=mean_pct, fill=n_pos_marker), stat='identity', width=1) + 
    facet_grid(t_type + day ~ car) + 
    scale_y_continuous(expand=c(0,0)) + 
    scale_x_discrete(expand=c(0,0)) +
    scale_fill_brewer('Number of Exh.\nMarkers Present', palette='YlOrRd') + 
    theme_minimal() +
    theme(axis.title.x=element_blank(),
        axis.text.x=element_blank(),
        axis.ticks.x=element_blank()) +
    geom_vline(xintercept=0:7-0.5) +
        labs(x="CD4/CD8 and Day", y='CAR', title='Fraction of Cells (Donor 2)') +
    coord_polar("y", start=0)

ggplot(marker_freq[donor == 2 & k562 != 'none' & n_pos_marker != 7 & k562 == 'cd19+']) + 
    geom_bar(aes(x=1, y=mean_pct, fill=n_pos_marker), stat='identity', width=1) + 
    facet_grid(t_type + day ~ car) + 
    scale_y_continuous(expand=c(0,0)) + 
    scale_x_discrete(expand=c(0,0)) +
    scale_fill_brewer('Number of Exh.\nMarkers Present', palette='YlOrRd') + 
    theme_minimal() +
    theme(axis.title.x=element_blank(),
        axis.text.x=element_blank(),
        axis.ticks.x=element_blank()) +
    geom_vline(xintercept=0:7-0.5) +
    labs(x="CD4/CD8 and Day", y='CAR', title='Fraction of Cells (Donor 2)') +
    coord_polar("y", start=0)
LS0tCnRpdGxlOiAiRXhoYXVzdGlvbiBQbG90cyBmb3IgQXJyYXllZCBTY3JlZW5zIgpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sKLS0tCgojIExvYWQgRGF0YSAKYGBge3J9CmxpYnJhcnkoZ2dwbG90MikKbGlicmFyeShkYXRhLnRhYmxlKQpsaWJyYXJ5KHNjYWxlcykKbGlicmFyeShSQ29sb3JCcmV3ZXIpCgpkYXRhX2RpciA8LSBoZXJlOjpoZXJlKCcuLicsJ2RhdGEnKQpsb2FkKGZpbGUucGF0aChkYXRhX2RpciwgJ2V4aC5zYW1wbGVkLlJkYXRhJykpCgpjYXJfc2V0IDwtIGMoJzQxQkInLCdDRDI4JywnQkFGRi1SJywnQ0Q0MCcsJ1RBQ0knKQoKCiMgbWFwIGRheSAwIHRvIGJvdGggcGx1cyBhbmQgbWludXMKbWFwX2RheV8wIDwtIGZ1bmN0aW9uKGRmKSB7CiAgcmV0dXJuKHJiaW5kKAogICAgZGZbazU2MiE9J25vbmUnXSwKICAgIGRmW2s1NjI9PSdub25lJ11bLCBrNTYyIDo9ICdjZDE5KyddLAogICAgZGZbazU2Mj09J25vbmUnXVssIGs1NjIgOj0gJ2NkMTktJ10KICApKQp9CmBgYAoKIyMgQXNzZXNzIE1hcmtlciBUaHJlc2hvbGRzCgpgYGB7ciBmaWcud2lkdGg9MTQsIGZpZy5oZWlnaHQ9OH0KIyB0YWJsZSBvZiB0aHJlc2hvbGRzIGNob3NlbgptYXJrZXJfdGhyZXNob2xkcyA8LSByYmluZCgKICAgIGMoZXhoX29wdF9jZDQkbWFya2VyX3RocmVzaG9sZHMsIHRfdHlwZT0nY2Q0JyksCiAgICBjKGV4aF9vcHRfY2Q4JG1hcmtlcl90aHJlc2hvbGRzLCB0X3R5cGU9J2NkOCcpKQptYXJrZXJfdGhyZXNob2xkcyA8LSBtZWx0KAogICAgZGF0YS50YWJsZShtYXJrZXJfdGhyZXNob2xkcyksIGlkLnZhcnM9YygndF90eXBlJykpCm1hcmtlcl90aHJlc2hvbGRzWywgdmFsdWUgOj0gdW5saXN0KHZhbHVlKV0KbWFya2VyX3RocmVzaG9sZHNbLCB0X3R5cGUgOj0gdW5saXN0KHRfdHlwZSldCm1hcmtlcl90aHJlc2hvbGRzIDwtIHJiaW5kKAogICAgY29weShtYXJrZXJfdGhyZXNob2xkc1ssIGs1NjIgOj0gJ2NkMTkrJ10pLCAKICAgIGNvcHkobWFya2VyX3RocmVzaG9sZHNbLCBrNTYyIDo9ICdjZDE5LSddKSkKCmJsdWVfc2hhZGVzIDwtIGJyZXdlci5wYWwoNywgIllsR25CdSIpWzM6N10KCiMgYXNzZXNzIG1hcmtlciB0aHJlc2hvbGRzCmdncGxvdChleGhfZHRbazU2MiAlaW4lIGMoJ2NkMTkrJywnY2QxOS0nKSAmIHZhcmlhYmxlICE9ICd6b21iaWVfdCcgJiAKICAgIHZhcmlhYmxlICVpbiUgbmFtZXMoZXhoX29wdF9jZDQkbWFya2VyX3RocmVzaG9sZHMpXSkgKyAKICAgIGdlb21fZGVuc2l0eShhZXMoeD12YWx1ZSwgY29sb3I9ZmFjdG9yKGRheSkpKSArIAogICAgc2NhbGVfeF9jb250aW51b3VzKGxpbWl0cz1jKC0xMDAwLDUwMDApKSArIAogICAgdGhlbWVfbWluaW1hbCgpICsKICAgIGdlb21fdmxpbmUoZGF0YT1tYXJrZXJfdGhyZXNob2xkc1t2YXJpYWJsZSAhPSAnem9tYmllX3QnXSwgYWVzKHhpbnRlcmNlcHQ9dmFsdWUpKSArCiAgICBmYWNldF9ncmlkKHRfdHlwZStrNTYyfnZhcmlhYmxlLCBzY2FsZT0nZnJlZScpICsgCiAgICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzPWJsdWVfc2hhZGVzKQpgYGAKCiMjIFN1bW1hcnkgU3RhdHMgYnkgTUZJLCAlIFBvc2l0aXZlLCBhbmQgJSBQb3NpdGl2ZSBNRkkKCmBgYHtyLCBmaWcud2lkdGg9MTQsIGZpZy5oZWlnaHQ9OH0KCiMgd2hpY2ggbWFya2VycyBmb3Igd2hpY2ggc3VtbWFyeSBzdGF0cwp0b3RhbF9tZmkgPC0gYygnY2QzOV90JywnbXljX3QnLCAncGQxX3QnKQpwb3NfbWZpIDwtIGMoJ3RpbTNfdCcsJ2xhZzNfdCcsJ2NkMzlfdCcsJ3BkMV90JykKcG9zX3BjdCA8LSBjKCd0aW0zX3QnLCdsYWczX3QnLCdjZDM5X3QnLCAncGQxX3QnKQoKcGN0X3Bvc19tYXJrZXJzIDwtIGV4aF9kdFt2YXJpYWJsZSAlaW4lIHBvc19wY3QsCiAgbGlzdChwY3RfcG9zPSBzdW0oZ3RfdGhyZXNoKS8uTiksCiAgYnk9YygncGxhdGUnLCd3ZWxsJywnZGF5JywnazU2MicsJ2Rvbm9yJywnY2FyJywndmFyaWFibGUnLCd0X3R5cGUnKV1bLCAKICAgIGxpc3QobWVhbl9wY3RfcG9zPSBtZWFuKHBjdF9wb3MpLCBzZF9wY3RfcG9zPSBzZChwY3RfcG9zKSksCiAgICBieT1jKCdkYXknLCdrNTYyJywnZG9ub3InLCdjYXInLCd2YXJpYWJsZScsJ3RfdHlwZScpXQpwY3RfcG9zX21hcmtlcnMgPC0gbWFwX2RheV8wKHBjdF9wb3NfbWFya2VycykKCnBvc19tZmlfbWFya2VycyA8LSBleGhfZHRbdmFyaWFibGUgJWluJSBwb3NfbWZpLAogIGxpc3QocG9zX21maV93ZWxsPSBtZWFuKHZhbHVlW2d0X3RocmVzaD09VF0pLCBwb3NfbWZpX3dlbGxfc2Q9IHNkKHZhbHVlW2d0X3RocmVzaD09VF0pKSwgCiAgYnk9YygncGxhdGUnLCd3ZWxsJywnZGF5JywnazU2MicsJ2Rvbm9yJywnY2FyJywndmFyaWFibGUnLCd0X3R5cGUnKV1bLAogICAgYDo9YChtZWFuX21maV9wb3M9IG1lYW4ocG9zX21maV93ZWxsKSwgc2RfbWZpX3Bvcz0gc2QocG9zX21maV93ZWxsKSksCiAgICAgICAgYnk9YygnZGF5JywnazU2MicsJ2Rvbm9yJywnY2FyJywndmFyaWFibGUnLCd0X3R5cGUnKV0gIAogICAgCnBjdF9wb3NfbWFya2Vyc1ssIG1lYW5fZGlmZl9wY3RfcG9zIDo9IG1lYW5fcGN0X3Bvcy1tZWFuKG1lYW5fcGN0X3BvcywgbmEucm09VCksIAogICAgYnk9YygnZGF5JywnazU2MicsJ2Rvbm9yJywndmFyaWFibGUnLCd0X3R5cGUnKV0KCnBjdF9wb3NfbGJscyA8LSBwY3RfcG9zX21hcmtlcnNbIWlzLm5hKHZhcmlhYmxlKSAmICFpcy5uYShkb25vcikgJiBrNTYyID09ICdjZDE5KycsCiAgbGlzdCh2YXJfbWVhbiA9IG1lYW4obWVhbl9wY3RfcG9zLCBuYS5ybT1UKSksIGJ5PWMoJ2s1NjInLCdkYXknLCd2YXJpYWJsZScsJ2Rvbm9yJywndF90eXBlJyldWywKICAgIHZhcmlhYmxlIDo9IGFzLmNoYXJhY3Rlcih2YXJpYWJsZSldCgojIGFsbCBDQVJzLCBDRDE5KyBvbmx5CgpnZ3Bsb3QocGN0X3Bvc19tYXJrZXJzWyFpcy5uYSh2YXJpYWJsZSkgJiAhaXMubmEoZG9ub3IpICYgazU2MiA9PSAnY2QxOSsnICYgdmFyaWFibGUgJWluJSBwb3NfcGN0XSkgKyAKICAgIGdlb21fYmFyKGFlcyh4PWNhciwgeT1tZWFuX2RpZmZfcGN0X3BvcywgZmlsbD12YXJpYWJsZSksIHN0YXQ9J2lkZW50aXR5JykgKwogICAgZ2VvbV9saW5lcmFuZ2UoYWVzKHg9Y2FyLCB5bWluPW1lYW5fZGlmZl9wY3RfcG9zLXNkX3BjdF9wb3MsIHltYXg9bWVhbl9kaWZmX3BjdF9wb3Mrc2RfcGN0X3BvcykpICsKICAgIGdlb21fdGV4dChkYXRhPXBjdF9wb3NfbGJscywgCiAgICAgICAgYWVzKGxhYmVsPXBlcmNlbnQocm91bmQodmFyX21lYW4sMykpKSwgeT1JbmYsIHg9LUluZiwgaGp1c3Q9MCwgdmp1c3Q9MSkgKyAKICAgIGZhY2V0X2dyaWQodmFyaWFibGUrZG9ub3J+ZGF5K3RfdHlwZSwgc2NhbGVzPSdmcmVlJykgKwogICAgdGhlbWVfbWluaW1hbChiYXNlX3NpemU9MTgpICsgc2NhbGVfeV9jb250aW51b3VzKGxhYmVscyA9IHBlcmNlbnRfZm9ybWF0KGFjY3VyYWN5ID0gMSkpICsKICAgIHRoZW1lKGF4aXMudGV4dC54PWVsZW1lbnRfdGV4dChhbmdsZSA9IDkwLCBoanVzdCA9IDEpKSArCiAgICBsYWJzKHg9J0NBUicsIHk9J0NoYW5nZSBpbiAlIFBvc2l0aXZlJywgdGl0bGU9J1BjdCAlIGluIEV4aGF1c3Rpb24gTWFya2VyIGZyb20gQXZlcmFnZSBDQVIgKEFsbCBDQVJzKScpICsKICAgIGdlb21faGxpbmUoeWludGVyY2VwdD0wKSArCiAgICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQ9LUluZikKCiMgc2VsZWN0ZWQgY2FyIHNldCBvbmx5LCBDRDE5KyBvbmx5CgpwY3RfcG9zX21hcmtlcnNbY2FyICVpbiUgY2FyX3NldCwgbWVhbl9kaWZmX3BjdF9wb3MgOj0gbWVhbl9wY3RfcG9zLW1lYW4obWVhbl9wY3RfcG9zLCBuYS5ybT1UKSwgCiAgICBieT1jKCdkYXknLCdrNTYyJywnZG9ub3InLCd2YXJpYWJsZScsJ3RfdHlwZScpXQoKcGN0X3Bvc19sYmxzIDwtIHBjdF9wb3NfbWFya2Vyc1tjYXIgJWluJSBjYXJfc2V0ICYgIWlzLm5hKHZhcmlhYmxlKSAmICFpcy5uYShkb25vcikgJiBrNTYyID09ICdjZDE5KycsCiAgbGlzdCh2YXJfbWVhbiA9IG1lYW4obWVhbl9wY3RfcG9zLCBuYS5ybT1UKSksIGJ5PWMoJ2s1NjInLCdkYXknLCd2YXJpYWJsZScsJ2Rvbm9yJywndF90eXBlJyldWywKICAgIHZhcmlhYmxlIDo9IGFzLmNoYXJhY3Rlcih2YXJpYWJsZSldCgpnZ3Bsb3QocGN0X3Bvc19tYXJrZXJzW2NhciAlaW4lIGNhcl9zZXQgJiAhaXMubmEodmFyaWFibGUpICYgIWlzLm5hKGRvbm9yKSAmIGs1NjIgPT0gJ2NkMTkrJyAmIHZhcmlhYmxlICVpbiUgcG9zX3BjdF0pICsgCiAgICBnZW9tX2JhcihhZXMoeD1jYXIsIHk9bWVhbl9kaWZmX3BjdF9wb3MsIGZpbGw9dmFyaWFibGUpLCBzdGF0PSdpZGVudGl0eScpICsKICAgIGdlb21fbGluZXJhbmdlKGFlcyh4PWNhciwgeW1pbj1tZWFuX2RpZmZfcGN0X3Bvcy1zZF9wY3RfcG9zLCB5bWF4PW1lYW5fZGlmZl9wY3RfcG9zK3NkX3BjdF9wb3MpKSArCiAgICBnZW9tX3RleHQoZGF0YT1wY3RfcG9zX2xibHMsIAogICAgICAgIGFlcyhsYWJlbD1wZXJjZW50KHJvdW5kKHZhcl9tZWFuLDMpKSksIHk9SW5mLCB4PS1JbmYsIGhqdXN0PTAsIHZqdXN0PTEpICsgCiAgICBmYWNldF9ncmlkKHZhcmlhYmxlK2Rvbm9yfnRfdHlwZSArIGRheSwgc2NhbGVzPSdmcmVlJykgKwogICAgdGhlbWVfbWluaW1hbChiYXNlX3NpemU9MTgpICsgc2NhbGVfeV9jb250aW51b3VzKGxhYmVscyA9IHBlcmNlbnRfZm9ybWF0KGFjY3VyYWN5ID0gMSkpICsKICAgIHRoZW1lKGF4aXMudGV4dC54PWVsZW1lbnRfdGV4dChhbmdsZSA9IDkwLCBoanVzdCA9IDEpKSArCiAgICBsYWJzKHg9J0NBUicsIHk9J0NoYW5nZSBpbiAlIFBvc2l0aXZlJywgdGl0bGU9J1BjdCAlIGluIEV4aGF1c3Rpb24gTWFya2VyIGZyb20gQXZlcmFnZSBDQVIgKFNlbGVjdGVkIENBUnMpJykgKwogICAgZ2VvbV9obGluZSh5aW50ZXJjZXB0PTApICsKICAgIGdlb21fdmxpbmUoeGludGVyY2VwdD0tSW5mKQoKYGBgCgojIyBOdW1iZXIgb2YgcG9zaXRpdmUgbWFya2VycyBwZXIgY2VsbAoKYGBge3IsICBmaWcud2lkdGg9MTgsIGZpZy5oZWlnaHQ9N30KbWFya2VyX2N0IDwtIGV4aF9kdFt2YXJpYWJsZSAlaW4lIGMoJ3RpbTNfdCcsJ2xhZzNfdCcsJ2NkMzlfdCcsICdwZDFfdCcpLAogIGxpc3Qobl9wb3NfbWFya2VyPSBzdW0oZ3RfdGhyZXNoKSksIAogIGJ5PWMoJ3dlbGwnLCdwbGF0ZScsJ2RheScsJ1RpbWUnLCdjYXInLCdkb25vcicsJ2s1NjInLCd0X3R5cGUnKV0KCm1hcmtlcl9jdCA8LSBtYXJrZXJfY3RbLCBOIDo9IC5OLCBieT1jKCd3ZWxsJywncGxhdGUnLCdkYXknLCdjYXInLCdrNTYyJywndF90eXBlJyldW04gPiAxXQoKbWFya2VyX2N0IDwtIG1hcF9kYXlfMChtYXJrZXJfY3QpCgptYXJrZXJfZnJlcSA8LSBtYXJrZXJfY3RbLCBkYXRhLmZyYW1lKHRhYmxlKGZhY3RvcihuX3Bvc19tYXJrZXIsIGxldmVscz0gMDo0KSkpLCAKICBieT1jKCd3ZWxsJywncGxhdGUnLCdkYXknLCdjYXInLCdkb25vcicsJ2s1NjInLCd0X3R5cGUnKV0KbmFtZXMobWFya2VyX2ZyZXEpW25hbWVzKG1hcmtlcl9mcmVxKSA9PSAnVmFyMSddIDwtICduX3Bvc19tYXJrZXInCgptYXJrZXJfZnJlcVsgbl9wb3NfbWFya2VyICE9IDcsIHBjdCA6PSBGcmVxL3N1bShGcmVxKSwgCiAgYnk9Yygnd2VsbCcsJ3BsYXRlJywnZGF5JywnY2FyJywnZG9ub3InLCdrNTYyJywndF90eXBlJyldCgptYXJrZXJfZnJlcSA8LSBtYXJrZXJfZnJlcVssCiAgbGlzdChtZWFuX3BjdD0gbWVhbihwY3QsIG5hLnJtPVQpKSwKICBieT1jKCdkYXknLCdjYXInLCdkb25vcicsJ2s1NjInLCAnbl9wb3NfbWFya2VyJywndF90eXBlJyldCgpnZ3Bsb3QobWFya2VyX2ZyZXFbazU2MiAhPSAnbm9uZScgJiBuX3Bvc19tYXJrZXIgIT0gN10pICsgCiAgZ2VvbV9iYXIoYWVzKHg9Y2FyLCB5PW1lYW5fcGN0LCBmaWxsPW5fcG9zX21hcmtlciksIHN0YXQ9J2lkZW50aXR5JykgKyAKICBmYWNldF9ncmlkKGs1NjIgKyBkb25vciArIHRfdHlwZSB+IGRheSwgc2NhbGVzPSdmcmVlJykgKyAKICBzY2FsZV95X2NvbnRpbnVvdXMoZXhwYW5kPWMoMCwwKSkgKyAKICBzY2FsZV9maWxsX2JyZXdlcignTnVtYmVyIG9mIEV4aC5cbk1hcmtlcnMgUHJlc2VudCcsIHBhbGV0dGU9J1lsT3JSZCcpICsgCiAgdGhlbWVfbWluaW1hbCgpICsKICBsYWJzKHg9IkNBUiIsIHk9J0ZyYWN0aW9uIG9mIENlbGxzJykKCmdncGxvdChtYXJrZXJfZnJlcVtrNTYyICE9ICdub25lJyAmIG5fcG9zX21hcmtlciAhPSA3ICYgazU2MiA9PSAnY2QxOSsnXSkgKyAKICBnZW9tX2JhcihhZXMoeD1mYWN0b3IoZGF5KSwgeT1tZWFuX3BjdCwgZmlsbD1uX3Bvc19tYXJrZXIpLCBzdGF0PSdpZGVudGl0eScsIHdpZHRoPTEpICsgCiAgZmFjZXRfZ3JpZChkb25vciB+IHRfdHlwZSArIGNhciwgc2NhbGVzPSdmcmVlJykgKyAKICBzY2FsZV95X2NvbnRpbnVvdXMoZXhwYW5kPWMoMCwwKSwgbGFiZWxzID0gcGVyY2VudF9mb3JtYXQoYWNjdXJhY3kgPSAxKSkgKyAKICBzY2FsZV94X2Rpc2NyZXRlKGV4cGFuZD1jKDAsMCkpICsKICBzY2FsZV9maWxsX2JyZXdlcignTnVtYmVyIG9mIEV4aC5cbk1hcmtlcnMgUHJlc2VudCcsIHBhbGV0dGU9J1lsT3JSZCcpICsgCiAgdGhlbWVfbWluaW1hbCgpICsKICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQ9MDo3LTAuNSkgKwogIGdlb21faGxpbmUoeWludGVyY2VwdD1jKDAsMSkpICsKICBsYWJzKHg9IkNBUiIsIHk9J0ZyYWN0aW9uIG9mIENlbGxzJykKCiMgcGllIGNoYXJ0cwpnZ3Bsb3QobWFya2VyX2ZyZXFbZG9ub3IgPT0gMSAmIGs1NjIgIT0gJ25vbmUnICYgbl9wb3NfbWFya2VyICE9IDcgJiBrNTYyID09ICdjZDE5KyddKSArIAogICAgZ2VvbV9iYXIoYWVzKHg9MSwgeT1tZWFuX3BjdCwgZmlsbD1uX3Bvc19tYXJrZXIpLCBzdGF0PSdpZGVudGl0eScsIHdpZHRoPTEpICsgCiAgICBmYWNldF9ncmlkKHRfdHlwZSArIGRheSB+IGNhcikgKyAKICAgIHNjYWxlX3lfY29udGludW91cyhleHBhbmQ9YygwLDApKSArIAogICAgc2NhbGVfeF9kaXNjcmV0ZShleHBhbmQ9YygwLDApKSArCiAgICBzY2FsZV9maWxsX2JyZXdlcignTnVtYmVyIG9mIEV4aC5cbk1hcmtlcnMgUHJlc2VudCcsIHBhbGV0dGU9J1lsT3JSZCcpICsgCiAgICB0aGVtZV9taW5pbWFsKCkgKwogICAgdGhlbWUoYXhpcy50aXRsZS54PWVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBheGlzLnRleHQueD1lbGVtZW50X2JsYW5rKCksCiAgICAgICAgYXhpcy50aWNrcy54PWVsZW1lbnRfYmxhbmsoKSkgKwogICAgZ2VvbV92bGluZSh4aW50ZXJjZXB0PTA6Ny0wLjUpICsKICAgICAgICBsYWJzKHg9IkNENC9DRDggYW5kIERheSIsIHk9J0NBUicsIHRpdGxlPSdGcmFjdGlvbiBvZiBDZWxscyAoRG9ub3IgMiknKSArCiAgICBjb29yZF9wb2xhcigieSIsIHN0YXJ0PTApCgpnZ3Bsb3QobWFya2VyX2ZyZXFbZG9ub3IgPT0gMiAmIGs1NjIgIT0gJ25vbmUnICYgbl9wb3NfbWFya2VyICE9IDcgJiBrNTYyID09ICdjZDE5KyddKSArIAogICAgZ2VvbV9iYXIoYWVzKHg9MSwgeT1tZWFuX3BjdCwgZmlsbD1uX3Bvc19tYXJrZXIpLCBzdGF0PSdpZGVudGl0eScsIHdpZHRoPTEpICsgCiAgICBmYWNldF9ncmlkKHRfdHlwZSArIGRheSB+IGNhcikgKyAKICAgIHNjYWxlX3lfY29udGludW91cyhleHBhbmQ9YygwLDApKSArIAogICAgc2NhbGVfeF9kaXNjcmV0ZShleHBhbmQ9YygwLDApKSArCiAgICBzY2FsZV9maWxsX2JyZXdlcignTnVtYmVyIG9mIEV4aC5cbk1hcmtlcnMgUHJlc2VudCcsIHBhbGV0dGU9J1lsT3JSZCcpICsgCiAgICB0aGVtZV9taW5pbWFsKCkgKwogICAgdGhlbWUoYXhpcy50aXRsZS54PWVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBheGlzLnRleHQueD1lbGVtZW50X2JsYW5rKCksCiAgICAgICAgYXhpcy50aWNrcy54PWVsZW1lbnRfYmxhbmsoKSkgKwogICAgZ2VvbV92bGluZSh4aW50ZXJjZXB0PTA6Ny0wLjUpICsKICAgIGxhYnMoeD0iQ0Q0L0NEOCBhbmQgRGF5IiwgeT0nQ0FSJywgdGl0bGU9J0ZyYWN0aW9uIG9mIENlbGxzIChEb25vciAyKScpICsKICAgIGNvb3JkX3BvbGFyKCJ5Iiwgc3RhcnQ9MCkKYGBgCgo=